#include <QDebug>
#include <QSet>
#include <QStringList>
#include <QRegExp>
#include "texttablemodel.h"

TextTableModel::TextTableModel(QObject *parent) 
    : QAbstractTableModel(parent)
{
    
}

int TextTableModel::rowCount(const QModelIndex &parent) const
{
    Q_UNUSED(parent);
    return m_text.rowCount();
}

int TextTableModel::columnCount (const QModelIndex &parent) const
{
    Q_UNUSED(parent);
    return m_text.columnCount();
}

QVariant TextTableModel::data(const QModelIndex &index, int role) const
{
    if(!index.isValid())
        return QVariant();

    if(index.row() >= m_text.rowCount() || index.column() >= m_text.columnCount())
        return QVariant();

    if(role == Qt::DisplayRole  || role == Qt::EditRole)
        return m_text.cellAt(index.row(), index.column());
    else if(role == Qt::BackgroundRole)
        return m_rowColors[index.row()];
    else
        return QVariant();
}

QVariant TextTableModel::headerData(int section, Qt::Orientation orientation, int role) const
{
    if(role == Qt::DisplayRole) {
        if(orientation == Qt::Vertical)
            return section + 1;
        else
            return section < m_horizontalLables.size() ? m_horizontalLables[section] : QVariant();
    }
    else {
        return QVariant();
    }    
}

bool TextTableModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
    if(!index.isValid())
        return false;

    if(role == Qt::EditRole) {
        m_text.setCell(index.row(), index.column(), value.toString());
        emit dataChanged(index, index);
        return true;
    }
    else if(role == Qt::BackgroundRole) {
        m_rowColors[index.row()] = value.value<QBrush>();
        emit dataChanged(index, index);
    }
    
    return QAbstractTableModel::setData(index, value, role);    
}

Qt::ItemFlags TextTableModel::flags(const QModelIndex &index) const
{
    if (!index.isValid())
        return Qt::ItemIsEnabled;

    return QAbstractTableModel::flags(index) | Qt::ItemIsEditable;    
}

bool TextTableModel::insertRows(int row, int count, const QModelIndex &parent)
{
    Q_UNUSED(parent)

    beginInsertRows(QModelIndex(), row, row + count - 1);
    m_text.insertRows(row, count);

    for(int i = 0; i < count; i++)
        m_rowColors.insert(row, QBrush());

    endInsertRows();
    return true;    
}

bool TextTableModel::removeRows(int row, int count, const QModelIndex &parent)
{
    Q_UNUSED(parent)

    beginRemoveRows(QModelIndex(), row, row + count - 1);
    m_text.removeRows(row, count);

    for(int i = 0; i < count; i++)
        m_rowColors.removeAt(row);

    endRemoveRows();
    return true; 
}

bool TextTableModel::insertColumns(int column, int count, const QModelIndex &parent)
{
    Q_UNUSED(column)
    Q_UNUSED(count)
    Q_UNUSED(parent)
    return false;
}

bool TextTableModel::removeColumns(int column, int count, const QModelIndex &parent)
{
    Q_UNUSED(column)
    Q_UNUSED(count)
    Q_UNUSED(parent)
    return false;
}

void TextTableModel::setText(const StringTable &text)
{
    m_text = text;
    m_rowColors.clear();
    for(int i = m_text.rowCount() - 1; i >= 0; i--)
        m_rowColors << QBrush();

    if(!m_text.rowCount() || !m_text.columnCount())
        return;

    reset();
}

const StringTable& TextTableModel::text() const
{
    return m_text;
}

void TextTableModel::setHorizontalHeaderLabels(const QStringList &labels)
{
    m_horizontalLables = labels;
}

void TextTableModel::normalize()
{
    for(int i = m_text.rowCount() - 1; i >= 0; i--) {
        for(int j = m_text.columnCount() - 1; j >= 0; j--) {
            QString str = m_text.cellAt(i, j).simplified();
            m_text.setCell(i, j, str);
        }
    }

    emit dataChanged(index(0, 0), index(m_text.rowCount() - 1, m_text.columnCount() - 1));
}

void TextTableModel::filter(QString str, const QModelIndexList &list)
{
    QSet<int> rows;
    QRegExp rx(str);
               
    QModelIndex parent = list[0].parent();
    foreach(QModelIndex index, list) {
        if(rx.indexIn(data(index).toString()) != -1)
            rows << index.row();
    }

    for(int i = m_text.rowCount(); i >= 0; i--)
        if(rows.contains(i))
            removeRow(i);
}

